package com.siao.net.socket
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	/**
	 * Socket客户端
	 * @author SiaoLeon
	 */
	public class SocketClient
	{
		// -------------------------------------------------------------------------------------------------------- 静态常量
		
		// -------------------------------------------------------------------------------------------------------- 静态变量
		
		// -------------------------------------------------------------------------------------------------------- 静态方法
		
		// -------------------------------------------------------------------------------------------------------- 静态函数
		
		// -------------------------------------------------------------------------------------------------------- 属性
		
		/**
		 * Socket处理器
		 */
		public var handler:ISocketHandler;
		
		/**
		 * Socket数据解析器
		 */
		public var resolver:IDataResolver;
		
		/**
		 * Socket连接状态
		 * @return
		 */
		public function get connected():Boolean
		{
			return this.socket.connected;
		}
		
		private var _host:String;
		
		/**
		 * 地址
		 * @return
		 */
		public function get host():String
		{
			return this._host;
		}
		
		private var _port:int;
		
		/**
		 * 端口
		 * @return
		 */
		public function get port():int
		{
			return this._port;
		}
		
		// -------------------------------------------------------------------------------------------------------- 变量
		
		private var buffer:ByteArray;
		
		private var socket:Socket;
		
		// -------------------------------------------------------------------------------------------------------- 构造
		
		/**
		 * 构造函数
		 * @param host 主机地址
		 * @param port 主机端口
		 */
		public function SocketClient(host:String=null, port:int=0)
		{
			this.buffer = new ByteArray();
			
			this.socket = new Socket();
			this.socket.endian = Endian.BIG_ENDIAN;
			
			this.connect(host, port);
		}
		
		// -------------------------------------------------------------------------------------------------------- 方法
		
		/**
		 * 建立Socket连接
		 * @param host 主机地址或IP
		 * @param port 端口号
		 */
		public function connect(host:String, port:int):void
		{
			this._host = host;
			this._port = port;
			
			if (host != null && port != 0)
			{
				this.socket.addEventListener(Event.CONNECT, onEvent, false, 0, true);
				this.socket.addEventListener(Event.CLOSE, onEvent, false, 0, true);
				this.socket.addEventListener(IOErrorEvent.IO_ERROR, onEvent, false, 0, true);
				this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onEvent, false, 0, true);
				this.socket.addEventListener(ProgressEvent.SOCKET_DATA, onEvent, false, 0, true);
				this.socket.connect(host, port);
			}
		}
		
		/**
		 * 发送数据
		 * @param data 字节数据
		 */
		public function send(data:IBytesData):void
		{
			if (!this.socket.connected)
			{
				return;
			}
			
			if (this.resolver == null)
			{
				this.socket.writeBytes(data.read());
			}
			else
			{
				this.socket.writeBytes(this.resolver.pack(data));
			}
			
			this.socket.flush();
			
			if (this.handler)
			{
				this.handler.onFlush(data);
			}
		}
		
		/**
		 * 模拟服务器发送数据
		 * @param data 字节数据
		 */
		public function push(data:IBytesData):void
		{
			if (!this.socket.connected)
			{
				return;
			}
			
			if (this.resolver == null)
			{
				this.read(data.read());
			}
			else
			{
				this.read(this.resolver.pack(data));
			}
		}
		
		/**
		 * 关闭连接
		 */
		public function close():void
		{
			if (!this.socket.connected)
			{
				return;
			}
			
			if (this.handler)
			{
				this.handler.onClose();
			}
			
			this.socket.removeEventListener(Event.CONNECT, onEvent);
			this.socket.removeEventListener(Event.CLOSE, onEvent);
			this.socket.removeEventListener(IOErrorEvent.IO_ERROR, onEvent);
			this.socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onEvent);
			this.socket.removeEventListener(ProgressEvent.SOCKET_DATA, onEvent);
			this.socket.close();
			this.buffer.clear();
		}
		
		public function toString():String
		{
			return "[SocketClient(" + this.host + ":" + this.port + ")]";
		}
		
		// -------------------------------------------------------------------------------------------------------- 函数
		
		/**
		 * Socket对象事件处理
		 * @param event
		 */
		private function onEvent(event:Event):void
		{
			switch (event.type)
			{
				case Event.CONNECT:
					if (this.handler != null)
					{
						this.handler.onConnect();
					}
					break;
				
				case Event.CLOSE:
					if (this.handler != null)
					{
						this.handler.onDisconnect();
					}
					break;
				
				case IOErrorEvent.IO_ERROR:
					if (this.handler != null)
					{
						this.handler.onIoError();
					}
					break;
				
				case SecurityErrorEvent.SECURITY_ERROR:
					if (this.handler != null)
					{
						this.handler.onSecurityError();
					}
					break;
				
				case ProgressEvent.SOCKET_DATA:
					var bytes:ByteArray = new ByteArray();
					this.socket.readBytes(bytes);
					this.read(bytes);
					break;
			}
		}
		
		/**
		 * 读取Socket对象数据
		 */
		private function read(bytes:ByteArray):void
		{
			if (!this.socket.connected)
			{
				return;
			}
			
			if (this.resolver == null)
			{
				this.handler.onRecive(bytes);
				return;
			}
			
			var position:uint = this.buffer.position;
			this.buffer.position = this.buffer.length;
			this.buffer.writeBytes(bytes);
			this.buffer.position = position;
			
			while (this.resolver.isContains(this.buffer))
			{
				var data:IBytesData = this.resolver.parse(this.buffer);
				
				if (this.handler != null)
				{
					this.handler.onRecive(data);
				}
			}
			
			if (this.buffer.bytesAvailable <= 0)
			{
				this.buffer.clear();
			}
		}
	
	}
}
